﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.ComponentModel.Composition;
using Steve.UI.Administration.Models;
using AutoMapper;
using System.Threading.Tasks;
using System.Diagnostics.CodeAnalysis;

namespace Steve.UI.Administration.Controllers
{
    public class ContentManagementControllerBase : AsyncController
    {
        protected const int DefaultSimilarCount = 10;
        
        [Import]
        public ContentRepository ContentRepository { get; set; }
        [Import]
        public ContentAdministrationRepository ContentAdministrationRepository { get; set; }
        [Import]
        public ContentTypeRepository ContentTypeRepository { get; set; }
        [ImportMany(typeof(ContentDataHandlerBase))]
        public IEnumerable<Lazy<ContentDataHandlerBase, IDictionary<string, object>>> DataHandlers { get; set; }
        [Import]
        public ISearchIndexService Index { get; set; }

        Task _rebuildTask;

        //TODO: async like cat cache?
        public virtual ActionResult RebuildSearchIndex()
        {
            Index.RebuildIndex();

            return new EmptyResult();
        }

        public virtual void SimilarityCacheRebuildAsync()
        {
            AsyncManager.OutstandingOperations.Increment();

            _rebuildTask = new Task(() =>
            {
                ContentAdministrationRepository.RebuildContentSimilarityCache();
                AsyncManager.OutstandingOperations.Decrement();
            });

            _rebuildTask.Start();
        }

        public virtual ActionResult SimilarityCacheRebuildCompleted()
        {
            _rebuildTask.Dispose();

            return new EmptyResult();
        }

        [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
        public virtual ActionResult ContentExplorer(string contentTypeName = null)
        {
            //TODO: handle this filtering...
            if (contentTypeName != null) throw new NotSupportedException("Filtering by content type is not yet supported.");

            return View("ContentExplorer");
        }

        [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
        [ChildActionOrHttpPost]
        public virtual ActionResult ContentExplorerDirectory(string path, string contentTypeName = null)
        {
            //TODO: handle this filtering...
            if (contentTypeName != null) throw new NotSupportedException("Filtering by content type is not yet supported.");

            var model = ContentRepository.GetContentDirectoryRoot();

            if (!string.IsNullOrWhiteSpace(path)) model = model.NavigateToDirectory(path);

            return View("ContentExplorerDirectory", model);
        }

        [SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
        [HttpGet]
        public virtual ActionResult ContentDetail(Guid? id, int similarCount = DefaultSimilarCount)
        {
            if (id == null || id == Guid.Empty)
            {
                var model = new NewContentDetailModel();

                return View("NewContentDetail", model);
            }
            else
            {
                var model = new ExistingContentDetailModel();

                var content = ContentRepository.GetContent(id.Value, null, false);
                
                Mapper.Map(content, (ExistingContentDetailModel)model);

                model.Categories = string.Join(", ", ContentRepository.GetContentCategories(id.Value));
                model.SimilarContent = ContentRepository.GetContentSimilarToContent(id.Value, false, similarCount);

                return View("ExistingContentDetail", model);
            }
        }

        [ChildActionOrHttpPostAttribute]
        public virtual ActionResult ContentDataEdit(Guid? contentId, string contentTypeName)
        {
            if (contentId == null && string.IsNullOrWhiteSpace(contentTypeName)) throw new ArgumentException("Must pass either content ID or contentTypeName.");

            ContentType ct;
            Content c;

            if (!string.IsNullOrWhiteSpace(contentTypeName))
            {
                c = null;
                ct = ContentTypeRepository.GetContentType(contentTypeName);
            }
            else
            {
                c = ContentRepository.GetContent(contentId.Value, null, false);
                ct = ContentTypeRepository.GetContentType(c.ContentTypeName);                
            }

            return DataHandlers.Edit(ct, c);
        }

        [ActionName("ContentDetail")]
        [HttpPost]
        [RouteValueAbsent("id")]
        [ValidateInput(false)]
        public virtual ActionResult ContentDetailPost(NewContentDetailModel model)
        {
            if (model == null) throw new ArgumentNullException("model");

            if (!ModelState.IsValid)
            {
                return View("NewContentDetail", model);
            }

            var ct = ContentTypeRepository.GetContentType(model.ContentTypeName);
            var toSave = new Content();

            Mapper.Map(model, toSave);

            DataHandlers.SaveEditData(ct, toSave);

            var cats = GetCategories(model.Categories);

            ContentAdministrationRepository.SaveContentAndCategories(toSave, cats);

            return RedirectToAction("ContentExplorer", "ContentManagement");
        }

        private IEnumerable<string> GetCategories(string modelValue)
        {
            IEnumerable<string> cats;

            if (string.IsNullOrWhiteSpace(modelValue))
            {
                cats = new string[] { };
            }
            else
            {
                cats = modelValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(c => c.Trim()).Where(c => !string.IsNullOrWhiteSpace(c)).Distinct();
            }

            return cats;
        }

        [ActionName("ContentDetail")]
        [HttpPost]
        [RouteValuePresent("id")]
        [ValidateInput(false)]
        public virtual ActionResult ContentDetailPost(ExistingContentDetailModel model, Guid id)
        {
            if (model == null) throw new ArgumentNullException("model");

            if (!ModelState.IsValid)
            {
                //reattach this data since its readonly...
                model.SimilarContent = ContentRepository.GetContentSimilarToContent(id, false, DefaultSimilarCount);

                return View("ExistingContentDetail", model);
            }

            var ct = ContentTypeRepository.GetContentType(model.ContentTypeName);
            var toSave = new Content();

            Mapper.Map(model, toSave);

            DataHandlers.SaveEditData(ct, toSave);
            toSave.Id = id;
            var cats = GetCategories(model.Categories);

            ContentAdministrationRepository.SaveContentAndCategories(toSave, cats);

            return RedirectToAction("ContentExplorer", "ContentManagement");
        }
    }
}
